<?php
namespace Model;

use Lib, Dao;

class Email {
	private $dir = NULL;
	private $DFake = NULL;
	private $DEmail = NULL;
	private $DDistrust = NULL;
	private $DHistory = NULL;
	private $DBatch = NULL;

	private function __construct() {
		$this->dir = \Core\HHO::$config['data.root'] . '/Email';
		
		$this->DFake = new Dao\Fake();
		$this->DEmail = new Dao\Email();
		$this->DDistrust = new Dao\Distrust();
		$this->DHistory = new Dao\History();
		$this->DBatch = new Dao\Batch();
	}

	public function getBatch() {
		$batch = array();
		
		foreach ($this->DBatch->select(NULL, array('id')) as $item) {
			$batch[] = $item;
		}
		
		return $batch;
	}

	/**
	 * 将指定批次的邮箱地址导入至数据库中。
	 *
	 * @param string $batch
	 * @return boolean
	 */
	public function import($batch) {
		if (!is_file($this->dir . '/' . $batch . '.txt')) {
			return FALSE;
		}
		
		$result = $this->DBatch->select(array('batch' => $batch));
		if ($result->count == 0) {
			return FALSE;
		}
		
		// =============================================================
		$fake = array();
		
		foreach ($this->DFake->select(array('prefix' => '')) as $item) {
			$fake[] = $item['host'];
		}
		
		$lastId = $this->DEmail->select(NULL, array('id DESC'), 1);
		$lastId = $lastId[0]['id'];
		
		// =============================================================
		$loose = array('uo', 'un', 'ue', 'iu', 'in', 'on', 'eo', 'en', 'er', 'ou', 'ea', 'ar', 'ao', 'ei', 'ai', 'an', 'zh', 'ch', 'sh');
		$strict = array('uan', 'iao', 'ian', 'ang', 'ing', 'ong', 'eng', 'ear', 'zhu', 'zhi', 'zhe', 'zha', 'zho', 'chu', 'chi', 'che', 'cha', 'cho', 'shu', 'shi', 'she', 'sha', 'sho');
		
		$list = file($this->dir . '/' . $batch . '.txt');
		
		$email = $history = array();
		
		foreach ($list as $mail) {
			$mail = explode("\t", trim($mail));
			
			if (!filter_var($mail[0], FILTER_VALIDATE_EMAIL)) {
				continue;
			} elseif (!preg_match('/^[a-z0-9]/i', $mail[0])) {
				continue;
			}
			
			$prefix = strtolower(strtok($mail[0], '@'));
			$host = strtolower(strtok('@'));
			
			if (strlen($prefix) > 24 || strlen($host) > 24) {
				continue;
			} elseif (in_array($host, $fake)) {
				continue;
			}
			
			$result = $this->DFake->select(array('prefix' => $prefix, 'host' => $host));
			if ($result->count > 0) {
				continue;
			}
			
			$result = $this->DEmail->select(array('prefix' => $prefix, 'host' => $host));
			if ($result->count > 0) {
				continue;
			}
			
			// =============================================================
			$host0 = strtok($host, '.');
			$host1 = strtok('.');
			
			$len = strlen($prefix);
			$leng = strlen($host1);
			
			if (preg_match('/^[a-z]{2,100}\w*\d{2,8}$/', $prefix)) {
				// void
			} elseif (strpos($prefix, '-') !== FALSE) {
				// void
			} elseif (strpos($prefix, '_') !== FALSE) {
				// void
			} elseif (in_array($host, array('vip.qq.com', 'vip.163.com', 'vip.sohu.com', 'vip.sina.com', '263.net'))) {
				// void
			} elseif (preg_match('/^\d{11}$/', $prefix) && in_array($host, array('139.com', '188.com', '189.cn'))) {
				// void
			} elseif (preg_match('/^1(?:3|5|8)\d{9}$/', $prefix) && in_array($host, array('163.com', '126.com'))) {
				// void
			} elseif ($len > 3 && $len < 10 && count(Lib\String::strpos($prefix, $loose)) > 0) {
				// void
			} elseif ($len > 3 && $len < 12 && count(Lib\String::strpos($prefix, $loose)) > 1) {
				// void
			} elseif ($len > 3 && $len < 15 && count(Lib\String::strpos($prefix, $loose)) > 2) {
				// void
			} elseif ($len > 3 && $len < 18 && count(Lib\String::strpos($prefix, $loose)) > 3) {
				// void
			} elseif ($len > 3 && Lib\String::strpos($prefix, $strict) !== FALSE) {
				// void
			} elseif ($host0 == 'mail') {
				// void
			} elseif (preg_match('/^[1-9]\d{7,11}@qq\.com$/', $prefix . '@' . $host)) {
				// void
			} elseif ($len > 10 && count(count_chars($prefix, 1)) > $len * 0.7) {
				continue;
			} elseif ($len < 10 && count(count_chars($prefix, 1)) < $len * 0.5) {
				continue;
			} elseif (in_array($host, array('qq.com', '163.com', '126.com', 'foxmail.com', 'sohu.com', 'sina.cn', 'sina.com', 'sina.com.cn', 'hotmail.com', 'gmail.com', 'live.cn', '139.com', 'tom.com', 'msn.com', '21cn.com', 'yeah.net', 'yahoo.com', 'yahoo.cn', 'yahoo.com.cn', 'china.com'))) {
				if ($len <= 2) {
					continue;
				} elseif ($len > 15) {
					continue;
				} elseif (preg_match('/^\d{3,4}$/', $prefix)) {
					continue;
				} elseif (preg_match('/^[1234]{6,100}$/', $prefix)) {
					continue;
				}
			} else {
				if ($leng > 3 && $leng < 10 && Lib\String::strpos($host1, $loose) !== FALSE) {
					// void
				} elseif ($leng > 3 && Lib\String::strpos($host1, $strict) !== FALSE) {
					// void
				} elseif (!in_array($host1, array('com', 'cn', 'net', 'org', 'gov', 'cc', 'hk', 'biz', 'tw', 'name'))) {
					continue;
				} elseif ($prefix == $host1) {
					continue;
				} elseif ($leng > 3) {
					continue;
				} elseif (count(count_chars($host1, 1)) != $leng) {
					continue;
				}
			}
			
			// =============================================================
			$d = array();
			$d['id'] = ++$lastId;
			$d['batch'] = $batch;
			$d['prefix'] = $prefix;
			$d['host'] = $host;
			$d['name'] = isset($mail[1]) ? trim($mail[1]) : '';
			$d['birthday'] = isset($mail[2]) ? $mail[2] : 0;
			$d['birthday'] = $d['birthday'] ?  : 0;
			$d['activetime'] = isset($mail[3]) ? $mail[3] : 0;
			$d['activetime'] = $d['activetime'] ?  : 0;
			$d['active'] = $d['activetime'] ? 1 : 0;
			$d['province'] = isset($mail[5]) ? trim($mail[5]) : '';
			$d['city'] = isset($mail[6]) ? trim($mail[6]) : '';
			
			if (substr($batch, 0, 6) == '6ROOMS') { // 来自六间房的邮箱活跃不可靠。
				$d['active'] = $d['activetime'] = 0;
			}
			
			$email["$prefix@$host"] = $d;
			
			$d['activetime'] > 0 && $history[] = array('email' => $lastId, 'activetime' => $d['activetime'], 'activeip' => isset($mail[4]) ? $mail[4] : 0);
			
			if (count($email) >= 10000) {
				$this->DEmail->insert($email) && count($history) && $this->DHistory->insert($history);
				
				$email = $history = array();
			}
		}
		
		count($email) && $this->DEmail->insert($email) && count($history) && $this->DHistory->insert($history);
		
		return $this->DEmail->affect > 0 ? TRUE : FALSE;
	}

	public function count($batch) {
		$result = $this->DEmail->select(array('batch' => $batch), NULL, NULL, 'count(*)');
		
		return $result[0]['count(*)'];
	}

	public function delete($batch, $host = NULL, $email = NULL) {
		if ($email) {
			$email = explode('@', $email);
			
			$this->DFake->replace(array('host' => $email[1], 'prefix' => $email[0]));
			
			return $this->DEmail->delete(array('host' => $email[1], 'prefix' => $email[0]));
		} elseif ($host) {
			$this->DFake->replace(array('host' => $host));
			
			return $this->DEmail->delete(array('host' => $host));
		}
		
		return $this->DEmail->delete(array('batch' => $batch));
	}

	/**
	 * 邮箱异常，但不确定是否为非法邮箱地址所致
	 *
	 * @param string $email
	 * @param int $marktime
	 * @return boolean
	 */
	public function distrust($email, $marktime) {
		$email = explode('@', $email);
		
		if (count($this->DEmail->select(array('host' => $email[1], 'prefix' => $email[0]))) <= 0) {
			return FALSE;
		}
		
		return $this->DDistrust->replace(array('host' => $email[1], 'prefix' => $email[0], 'marktime' => $marktime));
	}

	public function addHistory($email, $activetime, $activeip, $label = 0) {
		$prefix = strtok($email, '@');
		$host = strtok('@');
		
		if (count($this->DEmail->select(array('prefix' => $prefix, 'host' => $host))) <= 0) {
			return FALSE;
		}
		
		if (count($this->DHistory->select(array('email' => $email, 'activetime' => $activetime))) > 0) {
			return TRUE;
		}
		
		$update = ["activetime = $activetime"];
		
		if (count($this->DHistory->select(array('email' => $email, 'label' => $label))) <= 0) {
			$update[] = 'active = active + 1';
		}
		
		if (!$this->DHistory->insert(array('label' => $label, 'email' => $email, 'activetime' => $activetime, 'activeip' => $activeip))) {
			return FALSE;
		}
		
		return $this->DEmail->update($update, array('prefix' => $prefix, 'host' => $host));
	}

	/**
	 * 获得指定的邮箱地址列表，并按最近活跃时间倒序和活跃次数倒序排序
	 *
	 * @param string $batch
	 * @param array $host
	 * @return array
	 */
	public function getEmail($batch = NULL, $host = NULL) {
		$where = array();
		
		$batch && $where['batch'] = $batch;
		$host && $where['host'] = $host;
		
		return $this->DEmail->select($where, 'activetime DESC, active DESC')->fetch();
	}

	/**
	 * 获得指定批次邮箱地址的主机分布数量统计，并按数量排序
	 *
	 * @param string $batch
	 * @param int $limit
	 * @param array $always
	 * @return array
	 */
	public function getHost($batch, $limit = 0, $always = array()) {
		$hosts = array();
		
		foreach ($this->DEmail->getHost($batch) as $key => $value) {
			if ($key < $limit) {
				// void
			} elseif (in_array($value['host'], $always ?  : array())) {
				// void
			} else {
				continue;
			}
			
			$hosts[$value['host']] = $value['num'];
		}
		
		return $hosts;
	}

	public static function getInstance() {
		static $instance = null;
		
		if (!$instance) {
			$instance = new self();
		}
		
		return $instance;
	}
}